#ifndef UTILS_H
#define UTILS_H

#include <algorithm>
#include <tuple>
#include <type_traits>

#include <utils/Concepts.h>

#include <boost/pfr.hpp>

/*
    放一些常用的const常数，及常用的函数

*/
namespace solar
{
    // SOLAR_PURE_FUNCTION constexpr auto invSqrt(double number) noexcept -> double
    // {
    //     // (enable only on IEEE 754)
    //     static_assert(std::numeric_limits<double>::is_iec559);

    //     auto const y =
    //         std::bit_cast<double>(0x5fe6ec85e7de30da - (std::bit_cast<std::uint64_t>(number) >>
    //         1));
    //     return y * (1.5 - (number * 0.5 * y * y));
    // }

    namespace detail
    {
        template <class S, std::size_t... Is, class Tup>
        constexpr auto toStructInternal(std::index_sequence<Is...> /*unused*/, Tup&& tup) -> S
        {
            return {static_cast<typename boost::pfr::tuple_element<Is, S>::type>(
                std::get<Is>(std::forward<Tup>(tup)))...};
        }
        template <class S, class Tup> constexpr auto toStruct(Tup&& tup) -> S
        {
            return toStructInternal<S>(
                std::make_index_sequence<std::min(
                    std::tuple_size<std::remove_reference_t<Tup>>{}.value,
                    boost::pfr::tuple_size<std::remove_reference_t<S>>{}.value)>{},
                std::forward<Tup>(tup));
        }

        template <class S, std::size_t... Is, class Tup>
        constexpr auto toStructInternal2(std::index_sequence<Is...> /*unused*/, Tup&& tup) -> S
        {
            return {std::get<Is>(std::forward<Tup>(tup))...};
        }
        template <class S, class Tup> constexpr auto toStruct2(Tup&& tup) -> S
        {
            return toStructInternal2<S>(
                std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tup>>{}>{},
                std::forward<Tup>(tup));
        }
    } // namespace detail

    /// @brief 结构体复制（输入为结构体）
    template <typename T1, Aggregate T2> constexpr auto structCopy(const T2& input) -> T1
    {
        if constexpr (std::is_aggregate_v<T1>)
        {
            return detail::toStruct<T1>(boost::pfr::structure_to_tuple(input));
        }
        else
        {
            return detail::toStruct2<T1>(boost::pfr::structure_to_tuple(input));
        }
    }

    /// @brief 结构体复制（输入为结构体）
    template <Aggregate T1, typename T2> constexpr void structCopy(const T1& input, T2& output)
    {
        if constexpr (std::is_aggregate_v<T2>)
        {
            output = detail::toStruct<T2>(boost::pfr::structure_to_tuple(input));
        }
        else
        {
            output = detail::toStruct2<T2>(boost::pfr::structure_to_tuple(input));
        }
    }

    template <typename T> struct FuncConverter;

    template <typename Ret, typename... Params> struct FuncConverter<Ret(Params...)>
    {
            template <typename... Args> static auto callback(Args... args) -> Ret
            {
                return func_(args...);
            }
            static std::function<Ret(Params...)> func_;
    };

    // Initialize the static member.
    template <typename Ret, typename... Params>
    std::function<Ret(Params...)> FuncConverter<Ret(Params...)>::func_;
} // namespace solar

#endif // UTILS_H
